package store.lunangangster.engine.impl.agenda;

import java.util.LinkedList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import store.lunangangster.bpmn.model.FlowElement;
import store.lunangangster.engine.impl.entity.ExecutionEntity;
import store.lunangangster.engine.impl.interceptor.CommandContext;

public class DefaultEngineAgenda implements NodeFlowEngineAgenda {

  private static final Logger log = LoggerFactory.getLogger(DefaultEngineAgenda.class);

  protected LinkedList<Runnable> operations = new LinkedList<>();
  protected CommandContext commandContext;  // 每一个根Command执行时，都有一个新的Agenda对应

  public DefaultEngineAgenda(CommandContext commandContext) {
    this.commandContext = commandContext;
  }

  @Override
  public boolean hasNext() {
    return !operations.isEmpty();
  }

  @Override
  public Runnable getNextOperation() {
    return operations.poll();
  }

  @Override
  public void addOperation(Runnable operation) {
    addOperation(operation, true);
  }

  @Override
  public void addOperation(Runnable operation, boolean printNativeLog) {
    operations.add(operation);

    if (operation instanceof AbstractOperation) {
      // 需要将Operation涉及到的Execution添加到CommandContext
      commandContext.addInvolvedExecution(((AbstractOperation) operation).getExecution());
    }
    if (printNativeLog) {
      log.debug("添加操作: {}", operation.getClass());
    }
  }

  @Override
  public void addDoElementBehaviorOperation(ExecutionEntity execution, FlowElement previousElement) {
    addOperation(new DoElementBehaviorOperation(execution, previousElement, commandContext));
  }

  @Override
  public void addTakeOutGoingSequenceFlowOperation(ExecutionEntity execution) {
    addOperation(new TakeOutGoingSequenceFlowOperation(execution, commandContext));
  }

  @Override
  public void addEndExecutionOperation(ExecutionEntity execution) {
    addOperation(new EndExecutionOperation(execution, commandContext));
  }

  @Override
  public void addTriggerExecutionOperation(ExecutionEntity execution) {
    addOperation(new TriggerExecutionOperation(execution, commandContext));
  }
}
